package com.garvin.gateway.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.garvin.dto.base.BaseResponseDto;
import com.garvin.gateway.mapper.GatewayRouteMapper;
import com.garvin.gateway.model.GatewayRoute;
import com.garvin.gateway.service.GatewayRouteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.net.URI;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 路由服务类
 *
 * @author : garvin
 * @version V1.0
 * @date : 2020年10月09日 13:51
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class GatewayRouteServiceImpl implements GatewayRouteService {

    @Resource
    private GatewayRouteMapper gatewayRouteMapper;

    @Override
    public BaseResponseDto saveRouteDefinition(RouteDefinition routeDefinition) {
        int save;
        Date date = new Date();
        BaseResponseDto responseDto = new BaseResponseDto();

        GatewayRoute byRouteId = getGatewayRouteByRouteId(routeDefinition.getId());
        byRouteId.setRouteId(routeDefinition.getId());
        byRouteId.setRouteOrder(routeDefinition.getOrder());
        byRouteId.setServiceUri(routeDefinition.getUri().toString());
        byRouteId.setPredicates(JSON.toJSONString(routeDefinition.getPredicates()));
        byRouteId.setFilters(JSON.toJSONString(routeDefinition.getFilters()));
        byRouteId.setMetaData(JSON.toJSONString(routeDefinition.getMetadata()));
        if (Objects.nonNull(byRouteId.getId())) {
            Example example = new Example(GatewayRoute.class);
            example.createCriteria().andEqualTo("routeId", byRouteId.getRouteId());
            byRouteId.setUpdatedTime(date);
            save = gatewayRouteMapper.updateByExampleSelective(byRouteId, example);
        } else {
            byRouteId.setStatus(true);
            byRouteId.setCreatedTime(date);
            save = gatewayRouteMapper.insert(byRouteId);
        }

        if (save > 0) {
            responseDto.success();
        } else {
            responseDto.fail();
        }
        return responseDto;
    }

    @Override
    public BaseResponseDto deleteRouteDefinition(String routeId) {
        BaseResponseDto responseDto = new BaseResponseDto();
        GatewayRoute gatewayRoute = new GatewayRoute();
        gatewayRoute.setStatus(true);
        gatewayRoute.setRouteId(routeId);
        int delete = gatewayRouteMapper.delete(gatewayRoute);
        if (delete > 0) {
            responseDto.success();
        } else {
            responseDto.fail();
        }
        return responseDto;
    }

    @Override
    public List<RouteDefinition> getRouteDefinition() {
        GatewayRoute gatewayRoute = new GatewayRoute();
        gatewayRoute.setStatus(true);
        List<GatewayRoute> gatewayRoutes = gatewayRouteMapper.select(gatewayRoute);
        return gatewayRoutes.stream().map(o -> {
            RouteDefinition routeDefinition = new RouteDefinition();
            try {
                JSONObject metadata = JSON.parseObject(o.getMetaData());
                List<FilterDefinition> filters = JSON.parseArray(o.getFilters(), FilterDefinition.class);
                List<PredicateDefinition> predicates = JSON.parseArray(o.getPredicates(), PredicateDefinition.class);
                routeDefinition.setId(o.getRouteId());
                routeDefinition.setOrder(o.getRouteOrder());
                routeDefinition.setPredicates(Objects.nonNull(predicates) ? predicates : new ArrayList<>());
                routeDefinition.setFilters(Objects.nonNull(filters) ? filters : new ArrayList<>());
                routeDefinition.setMetadata(Objects.nonNull(metadata) ? metadata : new LinkedHashMap<>());
                routeDefinition.setUri(new URI(o.getServiceUri()));
            } catch (Exception e) {
                log.error("", e);
            }
            return routeDefinition;
        }).collect(Collectors.toList());
    }

    private GatewayRoute getGatewayRouteByRouteId(String routeId) {
        GatewayRoute gatewayRoute = new GatewayRoute();
        gatewayRoute.setStatus(true);
        gatewayRoute.setRouteId(routeId);
        GatewayRoute one = gatewayRouteMapper.selectOne(gatewayRoute);
        return Objects.isNull(one) ? new GatewayRoute() : one;
    }
}
